package com.feeyo.groundservice.http.utils

import com.feeyo.groundservice.http.base.BaseObserver
import com.feeyo.groundservice.http.core.HttpResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onStart
import java.lang.reflect.Type

/**
 *作者：QLH on 2023-09-18
 *描述：
 */

/**订阅模式：方式一
 *
 * @param observer 观察者接口
 * **/
suspend fun <T> Flow<HttpResult<T>>.subscribe(observer: BaseObserver<T>) {

    this.flowOn(Dispatchers.Default)//切换线程
        .onStart {
            //在上游流开始之前被调用，可以发出额外元素,也可以处理其他事情，比如loading
            observer.onStart()
        }
        .collect {
            it.fold(
                onSuccess = { data ->
                    observer.onComplete(data)
                },
                onFail = { msg, code ->
                    observer.onError(code, msg)
                }
            )
        }
}

/**封装模式：方式二
 *
 * @param requestCode 请求代码
 * @param observer 观察者接口
 * **/
suspend fun <T> getData(
    requestCode: suspend (FlowCollector<HttpResult<T>>) -> Unit,
    observer: BaseObserver<T>
) {
    coroutineScope {
        flow {

            requestCode(this)
        }
            .flowOn(Dispatchers.Default)//切换线程
            .onStart {
                //在上游流开始之前被调用，可以发出额外元素,也可以处理其他事情，比如loading
                observer.onStart()
            }
            .collect {
                it.fold(
                    onSuccess = { data ->
                        observer.onComplete(data)
                    },
                    onFail = { msg, code ->
                        observer.onError(code, msg)
                    }
                )
            }
    }
}


private inline fun <R, T> HttpResult<T>.fold(
    onSuccess: (data: T?) -> R,
    onFail: (msg: String, code: Int) -> R
): R {
    return when (this) {
        is HttpResult.Failure -> onFail(message, code)
        is HttpResult.Success -> onSuccess(data)
    }
}


fun Any.toJson(): String = MoshiUtils.toJson(this)
fun <T> String.fromJson(cls: Class<T>): T? = MoshiUtils.fromJson(this, cls)
fun <T> String.fromJson(type: Type): T? = MoshiUtils.fromJson<T>(this, type)

 inline fun <reified T>String.listFromJson():MutableList<T> = MoshiUtils.listFromJson(this)

 inline fun <reified K, reified V>String.mapFromJson():MutableMap<K,V> =
     MoshiUtils.mapFromJson(this)